package me.pplay.playtalk.protocol;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedList;

import me.pplay.playtalk.data.Globals;
import me.pplay.playtalk.util.PlayTalkUtil;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.text.TextUtils;

public class PhbBackUp {
	public static final int 	 TLV_CODE_PBK=1000 ;/// 标志imsi_pbk.back的body

	public static final short 		TLV_CODE_USER=1011;//string
	public static final short 		TLV_CODE_MOBILE=1010;//string
	public static final short 		TLV_CODE_HOMENUM=1012;//string
	public static final short 		TLV_CODE_OFFICENUM=1013;//string
	public static final short 		TLV_CODE_FAXNUM=1014;//string
	public static final short 		TLV_CODE_EMAIL=1015;//string

	public static final int 	 CONTACT_TIME_DELAY=(100) ;   /// 每次写间隔
	public static final int 	 CONTACT_WRITE_COUNT=(5);      /// 每次写的条数

	public static final int 	 CONTACT_BUFF=(10*1024);  /// 10K内存用于TLV 和MD5运算缓存

	public static final int 	 CONTACT_MAGIC_CODE=0x0774660D;
	public static final int 	 CONTACT_VERSION=1;

	public static final int 	 CONTACT_MD5_LENGTH=(16);
	public static final int 	 CONTACT_IMSI_LENGTH=(16);
	public static final int 	 CONTACT_IMEI_LENGTH =(16);
	public static final int 	 CONTACT_MANUFACTORY_LENGTH=(8);
	public static final int 	 CONTACT_PHONETYPE_LENGTH=(8);
	public static final int 	 CONTACT_SHORTNAME_LENGTH=(8);
	public static final int 	 CONTACT_ACCUNT_LENGTH=(128);
	private LinkedList<PhbItem> list = new LinkedList<PhbItem>();
	private String phbName;
	public class PhbHead
	{
		public int magic=0x0774660D; //the magic code
		public int version=PhbBackUp.CONTACT_VERSION; //reserve space
		public byte[] md5 = new byte[PhbBackUp.CONTACT_MD5_LENGTH];
		public int createtime;//create time
		public int phbsyncStatus;//0:后台传 1：自动转，2：手动传
		public byte[] imsi = new byte[PhbBackUp.CONTACT_IMSI_LENGTH];
		public byte[] imei = new byte[PhbBackUp.CONTACT_IMEI_LENGTH];
		public byte[]  manufactory = new byte[PhbBackUp.CONTACT_MANUFACTORY_LENGTH];
		public byte[]  phonetype = new byte[PhbBackUp.CONTACT_PHONETYPE_LENGTH];
		public int appid=0;
		public byte[]  shortname = new byte[PhbBackUp.CONTACT_SHORTNAME_LENGTH];
		public byte[]  account = new byte[PhbBackUp.CONTACT_ACCUNT_LENGTH];
	}
	public class PhbItem
	{
		public String user="";
		public String mobile="";
		public String email="";
		public String homeNum="";
		public String birth="";//生日
		public byte nGender;		//性别，1男，0女
		public byte age;//
		public byte resevred1;
		public byte resevred2;
	}
	public PhbBackUp(Context mContext)
	{
		getPhoneContacts(mContext);
		
	}
	private int put32(byte[] buf, int pos, int data) {
		buf[pos + 0] = (byte) ((byte) (data >> 24) & 0xff);
		buf[pos + 1] = (byte) ((byte) (data >> 16) & 0xff);
		buf[pos + 2] = (byte) ((byte) (data >> 8) & 0xff);
		buf[pos + 3] = (byte) ((byte) (data) & 0xff);
		return 4;
	}
	public void updatePhb(Context mContext,String user,String imsi,String imei,DataCallBack datacallback)
	{
		byte[] buf = new byte[4];
		PhbHead head = new PhbHead();
		phbName = Globals.FILE_PATH_PHB + user+ "_phb.bak";
		File fd;
		int pos=0;
		RandomAccessFile fout;
		try {
			fd = new File(phbName);
			if(fd.isFile())
				fd.delete();
			fout = new RandomAccessFile(phbName,"rw");
			////write head////
			pos += writeFileSdcard(fout,head.magic);
			pos += writeFileSdcard(fout,head.version);
			pos += writeFileSdcard(fout,head.md5);
			pos += writeFileSdcard(fout,(int)System.currentTimeMillis()/1000);
			pos += writeFileSdcard(fout,head.phbsyncStatus);
			System.arraycopy(imsi.getBytes(), 0, head.imsi, 0, imsi.getBytes().length>15?15:imsi.getBytes().length);
			System.arraycopy(imei.getBytes(), 0, head.imei, 0, imei.getBytes().length>15?15:imei.getBytes().length);
			pos += writeFileSdcard(fout,head.imsi);
			pos += writeFileSdcard(fout,head.imei);
			pos += writeFileSdcard(fout,head.manufactory);
			pos += writeFileSdcard(fout,head.phonetype);
			pos += writeFileSdcard(fout,head.appid);
			pos += writeFileSdcard(fout,head.shortname);
			pos += writeFileSdcard(fout,head.account);
			pos += writeFileSdcard(fout,TLV_CODE_PBK);
			
			writeFileSdcard(fout,0);
			int itempos = 0;
			int total = 0;
			byte[] p = new byte[1024];
			for(PhbItem item:list){
				itempos=0;
				itempos += PlayTalkUtil.TLV_Encode(p, itempos, TLV_CODE_MOBILE, item.mobile.getBytes());
				itempos += PlayTalkUtil.TLV_Encode(p, itempos, TLV_CODE_USER, item.user.getBytes());

				total += itempos;
				writeFileSdcard( fout, p,itempos);
			} 
			
			fout.seek(pos);
			writeFileSdcard(fout,total);
			generatePhbFileMD5(fout,total+pos+4,head.md5);
			fout.seek(8);
			writeFileSdcard(fout,head.md5);
			fout.close();
			TpFile tpFile = new TpFile();
			tpFile.tp_file_upload(phbName, TpFile.FILE_TRANS_TYPE_PBK, 0, 0, datacallback);
			return; 
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			fd = new File(phbName);
			if(fd.isFile())
				fd.delete();
			e.printStackTrace();
		}
		
	}
	private byte[] limitMd5(byte[] b,int offset,int step) {
		
		if (b==null || offset<0 || offset>=b.length) {
			throw new IllegalArgumentException("Illegal arguments");
		}
		
		step = step<=0?10240:step;
		try {
			MessageDigest md51 = MessageDigest.getInstance("MD5");
			MessageDigest md52 = MessageDigest.getInstance("MD5");
			while (offset<b.length) {
				int realStep = b.length-offset>step?step:b.length-offset;
				md51.update(b, offset, realStep);
				offset = offset + realStep;
				md52.update(md51.digest());
			}
			return md52.digest();
		} catch (NoSuchAlgorithmException e) {
			throw new RuntimeException(e);
		}
	}
	

	
	private boolean generatePhbFileMD5(RandomAccessFile stream,int fileSize,byte[]outMd5)
	{
		int fileOffset = 8 + CONTACT_MD5_LENGTH;  /// MD5计算不用文件头的前34个字节
		fileSize -= fileOffset;
		byte[] buff = new byte[fileSize];
		
		try {
			stream.seek(fileOffset);
			if(stream.read(buff, 0, fileSize) != fileSize)
			{
				return false;
			}
			byte[] bts = limitMd5(buff,0,0);
			System.arraycopy(bts, 0,outMd5, 0, bts.length);
			return true;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
		/*
		byte[] _buff = new byte[CONTACT_BUFF];
		byte[] pMd5Buff ;
		int md5BuffCount = 0;
		int count = 0;
		byte[] pMd5TempBuff;
		int pMd5TempBuffPos=0;
		int readLength = 0;
		int fileOffset = 8 + CONTACT_MD5_LENGTH;  /// MD5计算不用文件头的前34个字节

		fileSize -= fileOffset;

		md5BuffCount = fileSize/CONTACT_BUFF;
		if(fileSize%CONTACT_BUFF != 0) 
			md5BuffCount++;

		if(md5BuffCount == 0) return false;

		pMd5Buff = new byte[(md5BuffCount*CONTACT_MD5_LENGTH)];
		if(pMd5Buff == null)
		{
			return false;
		}
	 	pMd5TempBuff = pMd5Buff;
		count = md5BuffCount;
		do
		{
			try {
				stream.seek(fileOffset);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}
			readLength = CONTACT_BUFF;
			if((count-1) == 0)
			{
				if(fileSize%CONTACT_BUFF != 0)
				{
					readLength = fileSize%CONTACT_BUFF;
				}
			}
			try {
				if(stream.read(_buff, 0, readLength) != readLength)
				{
					return false;
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return false;
			}

			_MD5(_buff,readLength,pMd5TempBuff,pMd5TempBuffPos);
			pMd5TempBuffPos += CONTACT_MD5_LENGTH;

			fileOffset += readLength;
		}while((--count)>0);
		_MD5(pMd5Buff,md5BuffCount*CONTACT_MD5_LENGTH,outMd5,0);
		return true;
		*/
	}
	private int _MD5(byte[] src,int srclen,byte[] dst,int dstPos)
	{
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return 0;
		}
		byte[] bts = md.digest(src);
		System.arraycopy(bts, 0,dst, dstPos, bts.length);
		return bts.length;
	}
	public int writeFileSdcard(RandomAccessFile fout, int value) {
		try {
			byte[] bytes = new byte[4];
			put32(bytes,0,value);
			fout.write(bytes);
			return 4;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	public int writeFileSdcard(RandomAccessFile fout, byte[] bytes,int byteCount) {
		try {
			fout.write(bytes, 0, byteCount);
			return byteCount;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
	public int writeFileSdcard(RandomAccessFile fout, byte[] bytes) {
		try {
			fout.write(bytes);
			return bytes.length;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}
    /**联系人显示名称**/  

    private static final int PHONES_DISPLAY_NAME_INDEX = 0;  

    /**电话号码**/  

    private static final int PHONES_NUMBER_INDEX = 1;  

    /**头像ID**/  

    private static final int PHONES_PHOTO_ID_INDEX = 2;  

    /**联系人的ID**/  

    private static final int PHONES_CONTACT_ID_INDEX = 3;  
	private static final String[] PHONES_PROJECTION = new String[] {

	    Phone.DISPLAY_NAME, Phone.NUMBER, Photo.PHOTO_ID,Phone.CONTACT_ID };
	/**得到手机通讯录联系人信息**/  

	private void getPhoneContacts(Context mContext) {

		ContentResolver resolver = mContext.getContentResolver();

		// 获取手机联系人

		Cursor phoneCursor = resolver.query(Phone.CONTENT_URI, PHONES_PROJECTION, null, null, null);

		if (phoneCursor != null) {

			while (phoneCursor.moveToNext()) {

				// 得到手机号码

				String phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX);

				// 当手机号码为空的或者为空字段 跳过当前循环

				if (TextUtils.isEmpty(phoneNumber))

					continue;

				// 得到联系人名称

				String contactName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);
				PhbItem item = new PhbItem();
				item.mobile = phoneNumber;
				item.user = contactName;
				list.add(item);

			}

			phoneCursor.close();

		}

	}  
}
